package jmcnet.libcommun.junit;

import java.security.Principal;
import java.util.ArrayList;
import java.util.List;

import org.acegisecurity.Authentication;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.context.SecurityContextImpl;
import org.acegisecurity.providers.ProviderManager;
import org.acegisecurity.providers.TestingAuthenticationProvider;
import org.acegisecurity.userdetails.UserDetails;
import org.apache.log4j.Logger;

public class AcegiBaseTestCase extends SpringBaseTestCase {
	private Logger log = Logger.getLogger(AcegiBaseTestCase.class);

	private TestUserDetails token=null;
	private TestUserDetails oldToken=null;
	
	public AcegiBaseTestCase(String testApplicationContextFileName, String testApplicationContextBeanName, String authenticationManagerName) {
		super(testApplicationContextFileName, testApplicationContextBeanName);
		
		remplacerAuthenticationManager(authenticationManagerName);
	}
	
	public AcegiBaseTestCase(String authenticationManagerName) {
		super();
		remplacerAuthenticationManager(authenticationManagerName);
	}
	
	@SuppressWarnings("unchecked")
	private void remplacerAuthenticationManager(String authenticationManagerName) {
		log.info("Mise en place de l'authenticationManager : '"+authenticationManagerName+"'");
		
		// Remplacement du AuthenticationManager par un AuthenticationManager de test
		ProviderManager providerManager = (ProviderManager) getContexte().getBean(authenticationManagerName);
		List list = new ArrayList();
		list.add(new TestingAuthenticationProvider());
		providerManager.setProviders(list);
	}
	
	public void setUserProfile(String login, String password, String[] roles) {
		// Mise en place de la security
		TestUserDetails token = new TestUserDetails(
                login, password, roles);
		
		affecterUserProfile(token);
	}
	
	private void affecterUserProfile(TestUserDetails newToken) {
		oldToken = token;
		token = newToken;
		
		/* TestingAuthenticationToken t=null;
		
		if (token != null) {
			t = new TestingAuthenticationToken(token.getUsername(), token.getPassword(), token.getAuthorities());
			t.setDetails(token);
		}
		*/
		
		SecurityContext secureContext = new SecurityContextImpl();
        secureContext.setAuthentication((Authentication) token);
        SecurityContextHolder.setContext(secureContext);
	}
	
	public void restoreUserProfile() {
		affecterUserProfile(oldToken);
	}
	
	public Principal getPrincipal() {
		return SecurityContextHolder.getContext().getAuthentication();
	}
	
	// Ajout de static pour faire taire findbugs
	public static class TestUserDetails implements UserDetails, Authentication {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		private String login;
		private String password;
		private GrantedAuthority[] auth=null;
		private boolean authenticated=false;
		
		public TestUserDetails(String login, String password, String[] roles) {
			this.login = login;
			this.password = password;
			auth = new GrantedAuthority[roles.length];
			int i=0;
			for (String role : roles) {
				auth[i++] = new GrantedAuthorityImpl(role);
			}
		}

		public GrantedAuthority[] getAuthorities() {
			return auth;
		}

		public String getPassword() {
			return password;
		}

		public String getUsername() {
			return login;
		}

		public boolean isAccountNonExpired() {
			return true;
		}

		public boolean isAccountNonLocked() {
			return true;
		}

		public boolean isCredentialsNonExpired() {
			return true;
		}

		public boolean isEnabled() {
			return true;
		}

		public Object getCredentials() {
			return password;
		}

		public Object getDetails() {
			return null;
		}

		public Object getPrincipal() {
			return new Principal() {
				public String getName() {
					return login;
				}
			};
		}

		public boolean isAuthenticated() {
			return authenticated;
		}

		public void setAuthenticated(boolean arg0)
				throws IllegalArgumentException {
			authenticated = arg0;
		}

		public String getName() {
			return login;
		}
	}
}
